// SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
// SPDX-License-Identifier: GPL-3.0-only

package badger_dao_impl

import (
	"context"
	"encoding/json"
	"path/filepath"
	"sort"
	"time"

	"gitcode.com/openseaotter/so_proto_gen_go.git/auth_secret_api"
	"gitcode.com/openseaotter/so_server/storage/core"
	"gitcode.com/openseaotter/so_server/utils"
	"github.com/dgraph-io/badger/v4"
)

type AuthSecretItem struct {
	Username  string `json:"username"`
	Password  string `json:"password"`
	TimeStamp int64  `json:"timeStamp"`
}

func (item *AuthSecretItem) ToAuthSecret() *auth_secret_api.AuthSecretInfo {
	return &auth_secret_api.AuthSecretInfo{
		Username: item.Username,
		Password: item.Password,
	}
}

type AuthSecretItemList []*AuthSecretItem

func (a AuthSecretItemList) Len() int           { return len(a) }
func (a AuthSecretItemList) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a AuthSecretItemList) Less(i, j int) bool { return a[i].TimeStamp < a[j].TimeStamp }

type _AuthSecretDao struct {
	dbh *badger.DB
}

func NewAuthSecretDao() (core.AuthSecretDao, error) {
	dbPath := filepath.Join(utils.DATA_DIR_PATH, "secret")
	options := badger.DefaultOptions(dbPath)
	dbh, err := badger.Open(options)
	if err != nil {
		return nil, err
	}
	return &_AuthSecretDao{dbh: dbh}, nil
}

func (db *_AuthSecretDao) Insert(ctx context.Context, secret *auth_secret_api.AuthSecretInfo) error {
	return db.Update(ctx, secret)
}

func (db *_AuthSecretDao) Exist(ctx context.Context, username string) (bool, error) {
	txn := db.dbh.NewTransaction(false)
	defer txn.Discard()

	item, err := txn.Get([]byte(username))
	if err != nil {
		if err == badger.ErrKeyNotFound {
			return false, nil
		}
		return false, err
	}
	if item.IsDeletedOrExpired() {
		return false, badger.ErrKeyNotFound
	}

	return true, nil
}

func (db *_AuthSecretDao) Get(ctx context.Context, username string) (*auth_secret_api.AuthSecretInfo, error) {
	txn := db.dbh.NewTransaction(false)
	defer txn.Discard()

	item, err := txn.Get([]byte(username))
	if err != nil {
		return nil, err
	}
	if item.IsDeletedOrExpired() {
		return nil, badger.ErrKeyNotFound
	}
	value, err := item.ValueCopy(nil)
	if err != nil {
		return nil, err
	}
	secretItem := &AuthSecretItem{}
	err = json.Unmarshal(value, secretItem)
	if err != nil {
		return nil, err
	}
	return secretItem.ToAuthSecret(), nil
}

func (db *_AuthSecretDao) Update(ctx context.Context, secret *auth_secret_api.AuthSecretInfo) error {
	secretItem := &AuthSecretItem{
		Username:  secret.Username,
		Password:  secret.Password,
		TimeStamp: time.Now().UnixMilli(),
	}
	value, err := json.Marshal(secretItem)
	if err != nil {
		return err
	}

	txn := db.dbh.NewTransaction(true)
	defer txn.Discard()

	err = txn.Set([]byte(secret.Username), value)
	if err != nil {
		return err
	}
	return txn.Commit()
}

func (db *_AuthSecretDao) Remove(ctx context.Context, username string) error {
	txn := db.dbh.NewTransaction(true)
	defer txn.Discard()

	err := txn.Delete([]byte(username))
	if err != nil {
		return err
	}
	return txn.Commit()
}

func (db *_AuthSecretDao) List(ctx context.Context) ([]*auth_secret_api.AuthSecretInfo, error) {
	txn := db.dbh.NewTransaction(false)
	defer txn.Discard()

	iter := txn.NewIterator(badger.DefaultIteratorOptions)
	defer iter.Close()

	secretItemList := []*AuthSecretItem{}
	for iter.Rewind(); iter.Valid(); iter.Next() {
		item := iter.Item()
		if item.IsDeletedOrExpired() {
			continue
		}
		value, err := item.ValueCopy(nil)
		if err != nil {
			return nil, err
		}
		secretItem := &AuthSecretItem{}
		err = json.Unmarshal(value, secretItem)
		if err != nil {
			return nil, err
		}
		secretItemList = append(secretItemList, secretItem)
	}
	sort.Sort(sort.Reverse(AuthSecretItemList(secretItemList)))
	retList := []*auth_secret_api.AuthSecretInfo{}
	for _, secretItem := range secretItemList {
		retList = append(retList, secretItem.ToAuthSecret())
	}
	return retList, nil
}
